package edu.uis.csc478.spring09.threeoxen.persistence;

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectOutput;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.File;
import java.util.HashMap;

public class PersistenceManager {

    public static final String USER_REPOSITORY = "edu.uis.csc478.spring09.threeoxen.persistence.user.impl.UserRepositoryImpl";
    public static final String PANTRY_REPOSITORY = "edu.uis.csc478.spring09.threeoxen.persistence.pantry.impl.PantryRepositoryImpl";
    public static final String STORE_REPOSITORY = "edu.uis.csc478.spring09.threeoxen.persistence.store.impl.StoreRepositoryImpl";

    private HashMap repositories = new HashMap();

    private static PersistenceManager instance = new PersistenceManager();

    private PersistenceManager() {

    }

    public static PersistenceManager getInstance() {
        return instance;
    }

    public ObjectRepository getRepository(String repositoryKey) throws RepositoryPersistenceException {
        ObjectRepository repository = (ObjectRepository) repositories.get(repositoryKey);
        if(repository == null) {
            try {
                repository = loadRepository(repositoryKey);
            } catch(RepositoryPersistenceException e) {
                try {
                    repository = createNewRepository(repositoryKey);
                } catch(Exception e1) {
                    throw new RepositoryPersistenceException("Unable to instantiate request repository", e1);
                }
                this.repositories.put(repositoryKey, repository);
            }
        }
        return repository;
    }

    public ObjectRepository createNewRepository(String repositoryKey) throws RepositoryPersistenceException {
        if(repositoryKey.equals(USER_REPOSITORY)) {
            return PersistenceFactoryLoader.getInstance().getUserObjectFactory().createUserRepository();
        }else if(repositoryKey.equals(STORE_REPOSITORY)) {
            return PersistenceFactoryLoader.getInstance().getStoreObjectFactory().createStoreRepository();
        } else if(repositoryKey.equals(PANTRY_REPOSITORY)) {
            return PersistenceFactoryLoader.getInstance().getPantryObjectFactory().createPantryRepository();
        } else {
            throw new RepositoryPersistenceException("Unable to create repository for " + repositoryKey);
        }
    }

    public void updateRepository(ObjectRepository repository) throws RepositoryPersistenceException {
        this.repositories.put(repository.getClass().getName(), repository);
        storeRepository(repository.getClass().getName(), repository);
    }

    private ObjectRepository loadRepository(String repositoryKey) throws RepositoryPersistenceException {
        ObjectRepository repository = null;
        try {
            String filename = System.getProperty(repositoryKey + ".repo.filename");
            File file = new File(filename);
            if (!file.exists()) {
                throw new RepositoryPersistenceException("Repository file not found");
            }
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
            repository = (ObjectRepository) in.readObject();
            in.close();
        } catch (Exception e) {
            throw new RepositoryPersistenceException("Unable to load serializable repository from disk", e);
        }
        return repository;
    }

    private void storeRepository(String repositoryKey, ObjectRepository repository) throws RepositoryPersistenceException {
        try {
            String filename = System.getProperty(repositoryKey + ".repo.filename");
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream(filename));
            out.writeObject(repository);
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RepositoryPersistenceException("Unable to save serializable repository to disk with key " + repositoryKey, e);
        }
    }
}
